﻿using ComLib.ComType;
using DeviceCommon;
using DeviceControlClient;
using IPrinting;
using LogLib;
using System;

namespace KWindow.KPageCore
{
    public delegate void DoSomething(string outParams);

    public delegate void DoSomethingWrong(string outParams, string errorMsg);

    public class DeviceControl : IDisposable
    {
        /// <summary>
        /// 请求控制的设备名称
        /// </summary>
        private string _deviceName = "";

        private string _error = "";
        public string Error
        {
            get { return _error; }
        }

        private DeviceClient _client = new DeviceClient();

        #region To do something(delegate) after receive response from DeviceManageServer
        public DoSomething OnInitOK { get; set; }
        public DoSomething OnInitFailed { get; set; }
        public DoSomething OnExitOK { get; set; }
        public DoSomething OnExitFailed { get; set; }
        public DoSomething OnStartOK { get; set; }
        public DoSomething OnStartFailed { get; set; }
        public DoSomething OnStopOK { get; set; }
        public DoSomething OnStopFailed { get; set; }
        public DoSomething OnDone { get; set; }
        public DoSomethingWrong OnDoFailed { get; set; }
        public DoSomething OnWorkingDone { get; set; }
        public DoSomethingWrong OnWorkingFailed { get; set; }
        public DoSomething OnTestOK { get; set; }
        public DoSomething OnTestFailed { get; set; }
        public DoSomething OnTimeout { get; set; }
        public DoSomething OnCatchException { get; set; }
        #endregion

        public DeviceControl(string name)
        {
            _deviceName = name;
            InitDelegateFuncs();
        }

        /// <summary>
        /// 初始化所有的委托方法的对象
        /// 如果预测要使用该方法，必须在外部对其重新赋值
        /// </summary>
        private void InitDelegateFuncs()
        {
            // 以下委托必须在外部实现
            OnDoFailed = OnNotImplemented;
            OnDone = OnNotImplemented;
            OnWorkingDone = OnNotImplemented;
            OnWorkingFailed = OnNotImplemented;
            OnCatchException = OnNotImplemented;

            // 如果没有调用相关动作，以下委托可以不实现，
            // 但是如果有调用相关动作，必须实现对应动作请求返回后的回调
            // 否则将抛出异常
            OnInitOK = OnDefaultAction;
            OnInitFailed = OnDefaultAction;
            OnExitFailed = OnDefaultAction;
            OnExitOK = OnDefaultAction;
            OnStartFailed = OnDefaultAction;
            OnStartOK = OnDefaultAction;
            OnStopFailed = OnDefaultAction;
            OnStopOK = OnDefaultAction;
            OnTimeout = OnDefaultAction;
            OnTestFailed = OnDefaultAction;
            OnTestOK = OnDefaultAction;
        }

        private void OnDefaultAction(string outstring)
        {

        }

        private void OnNotImplemented(string delegateFunName)
        {
            throw new NotImplementedException();
        }

        private void OnNotImplemented(string delegateFunName, string error)
        {
            throw new NotImplementedException();
        }

        public bool Init()
        {
            _error = "客户端连接失败!";
            if (!_client.ConnectToServer())
            {
                Log.WriteAsync(_error);
                return false;
            }
            if (_client.Connected)
            {
                _client.ClientPackageReceived += NewPackage_Received;
                _client.ErrorReported += ClientError_Reported;
                Log.WriteAsync("客户端连接成功!");
                return true;
            }
            else
            {
                Log.WriteAsync("客户端连接失败!");
                return false;
            }
        }

        public void Exit()
        {
            Dispose();
        }

        private void ClientError_Reported(object sender, ClientErrorReportedEventArgs e)
        {
            _error = "客户端连接发生了异常: " + e.Message;
            Log.WriteAsync(_error);
        }

        private void NewPackage_Received(object sender, ClientPackageReceivedEventArgs e)
        {
            _error = "";
            ResponseMsgPackge package = e.Package;
            DeviceActionState state = package.ActionState;
            string outParams = package.OutParams;
            string errorMsg = package.Message;
            switch (state)
            {
                case DeviceActionState.InitOK:
                    OnInitOK(outParams);
                    break;
                case DeviceActionState.InitFailed:
                    OnInitFailed(errorMsg);
                    break;
                case DeviceActionState.ExitOK:
                    OnExitOK(outParams);
                    break;
                case DeviceActionState.ExitFailed:
                    OnExitFailed(errorMsg);
                    break;
                case DeviceActionState.StartOK:
                    OnStartOK(outParams);
                    break;
                case DeviceActionState.StartFailed:
                    OnStartFailed(errorMsg);
                    break;
                case DeviceActionState.StopOK:
                    OnStopOK(outParams);
                    break;
                case DeviceActionState.StopFailed:
                    OnStopFailed(errorMsg);
                    break;
                case DeviceActionState.Done:
                    OnDone(outParams);
                    break;
                case DeviceActionState.DoFailed:
                    OnDoFailed(outParams, errorMsg);
                    break;
                case DeviceActionState.WorkingDone:
                    OnWorkingDone(outParams);
                    break;
                case DeviceActionState.WorkingFailed:
                    OnWorkingFailed(outParams, errorMsg);
                    break;
                case DeviceActionState.TestOK:
                    OnTestOK(outParams);
                    break;
                case DeviceActionState.TestFailed:
                    OnTestFailed(errorMsg);
                    break;
                case DeviceActionState.Timeout:
                    OnTimeout(errorMsg);
                    break;
                case DeviceActionState.CatchException:
                    OnCatchException(errorMsg);
                    break;
                default:
                    break;
            }
        }

        #region Device general controls 请求控制设备的基本操作

        /// <summary>
        /// 请求控制设备执行某个动作
        /// </summary>
        /// <param name="action"></param>
        /// <param name="inParams"></param>
        protected void TakeAction(string action, string inParams)
        {
            if (!_client.Connected)
            {
                return;
            }
            RequestMsgPackge pack = new RequestMsgPackge();
            pack.DeviceName = _deviceName;
            pack.Action = action;
            pack.InParams = inParams;
            _client.SendRequest(pack);
        }

        /// <summary>
        ///  请求控制设备开始工作，
        ///  例如让身份证阅读器开始扫描
        /// </summary>    
        /// <param name="inParams">请求控制需要输入的参数</param>
        public void Start(string inParams = "")
        {
            TakeAction(DeviceAction.Start, inParams);
        }

        /// <summary>
        ///  请求控制设备停止工作，
        ///  例如让身份证阅读器停止扫描
        /// </summary>
        /// <param name="inParams">请求控制需要输入的参数</param>
        public void Stop(string inParams = "")
        {
            TakeAction(DeviceAction.Stop, inParams);
        }

        /// <summary>
        /// 请求设备执行操作(one motion)
        /// </summary>
        /// <param name="deviceName"></param>
        /// <param name="inParams"></param>
        public void Do(string inParams = "")
        {
            TakeAction(DeviceAction.DoAction, inParams);
        }

        /// <summary>
        /// 初始化设备(一般在业务流程中不用)
        /// </summary>
        /// <param name="inParams"></param>
        public void Init(string inParams = "")
        {
            TakeAction(DeviceAction.Init, inParams);
        }

        /// <summary>
        /// 卸载设备(一般在业务流程中不用)
        /// </summary>
        /// <param name="inParams"></param>
        public void UnInit(string inParams = "")
        {
            TakeAction(DeviceAction.Exit, inParams);
        }

        /// <summary>
        /// 测试设备动态库接口
        /// </summary>
        /// <param name="inParams">输入参数</param>
        public void Test(string inParams = "")
        {
            TakeAction(DeviceAction.Test, inParams);
        }

        public void ExitApp(string inParams = "")
        {
            TakeAction(DeviceAction.AppExit, inParams);
        }

        #endregion

        public void Dispose()
        {
            _client.Close();
        }
    }
}
